/*
	Arithmetic Logic Unit
*/
`include "define.v"
module alu 
(
	input 	wire	[63:00] 	    shift2,
	input   wire    [32:00]     	add_res_l  ,
    input   wire    [31:00]     	add_res_h  ,
    input   wire    [32:00]     	sub_res_l  ,   
    input   wire    [31:00]     	sub_res_h  ,
    input   wire    				subu_res_l ,
    input   wire    [31:00]     	subu_res_h ,
	input 	wire	[63:00] 	    operand1,
	input 	wire	[63:00] 	    operand2,
	//
	input	wire	[02:00]			funct3,
	input 	wire 					instr_branch,
	input 	wire 					branch_predic_res,
	input	wire	[10:00]			alu_op,
	input	wire	[01:00]			alu_shift_mode,
	//
	output 	wire 					branch_predic_fault,
	output	wire	[63:00] 		alu_output     		// ALU result. 
);
	wire			[63:00]			alu_operand1;
	wire			[63:00]			alu_operand2;
	wire			[63:00]			add_res;
	wire			[63:00]			sub_res;
	wire			[31:00]			subu_res;
	wire							slt_res;
	wire							sltu_res;
	wire			[63:00]			xor_res;
	wire			[63:00]			or_res;
	wire			[63:00]			and_res;
	wire			[63:00]			shift_res;
	wire			[63:00]			addw_res;
	wire			[63:00]			subw_res;
	wire			[63:00]			shiftw_res;

	assign	add_res[31:00]			= 	add_res_l[31:00]; 								// ADD
	assign	add_res[63:32]			= 	add_res_h + {31'b0,add_res_l[32]};


	assign	sub_res[31:00]			= 	sub_res_l[31:00]; 								// sub
	assign	sub_res[63:32]			= 	sub_res_h - {31'b0,sub_res_l[32]};


	// 	subu
	//	只需要最高位，低32位不用管
	assign	subu_res				= 	subu_res_h - {31'b0,subu_res_l};

	assign 	slt_res 				= 	sub_res[63];       						// SLT
	assign 	sltu_res 				= 	subu_res[31];                          	// SLTU
	assign 	xor_res 				= 	operand1 ^ operand2;                                         // XOR
	assign 	or_res 					= 	operand1 | operand2;                                         // OR
	assign 	and_res 				= 	operand1 & operand2;                                         // AND
	barrelShifterS					barrelShifterS												// Shift
	(
			.data_in				(operand1),
			.shift2					(shift2),
			.op						(alu_shift_mode),
			.shamt					(operand2[05:00]),
			.data_out				(shift_res)
	);
	assign	addw_res 				= 	{{32{add_res[31]}},add_res[31:00]}; 							// ADD
	assign	subw_res				= 	{{32{sub_res[31]}},sub_res[31:00]};
	assign	shiftw_res				= 	{{32{shift_res[31]}},shift_res[31:00]};

	assign				alu_output 	= 	(	{64{alu_op[00]}} 	& 	add_res			) |	
										(	{64{alu_op[01]}} 	& 	sub_res			) |		
										(	{64{alu_op[02]}} 	& 	{63'b0,slt_res}	) |
										(	{64{alu_op[03]}} 	& 	{63'b0,sltu_res}) |
										(	{64{alu_op[04]}} 	& 	xor_res			) |
										(	{64{alu_op[05]}} 	& 	or_res			) |
										(	{64{alu_op[06]}} 	& 	and_res			) |
										(	{64{alu_op[07]}} 	& 	shift_res		) |
										(	{64{alu_op[08]}} 	& 	addw_res		) |
										(	{64{alu_op[09]}} 	& 	subw_res		) |
										(	{64{alu_op[10]}} 	& 	shiftw_res		) ;

	wire    beq_res;
    wire    blt_res;
    wire    bltu_res;
    wire    branch_res;

	assign	beq_res		                    =	operand1 == operand2;

	assign	blt_res		                    = 	slt_res ;

	assign	bltu_res	                    = 	sltu_res;
                                       
	assign  branch_res	                    =	( funct3 == 3'b000 ? beq_res 	    : 1'b0 ) |		// BEQ
							                    ( funct3 == 3'b001 ? !beq_res 	: 1'b0 ) |		// BNE
							                    ( funct3 == 3'b100 ? blt_res 	    : 1'b0 ) |		// BLT
							                    ( funct3 == 3'b101 ? !blt_res 	: 1'b0 ) |		// BGE
							                    ( funct3 == 3'b110 ? bltu_res 	: 1'b0 ) |		// BLTU
							                    ( funct3 == 3'b111 ? !bltu_res 	: 1'b0 ) ;		// BGEU

	assign	branch_predic_fault		=   instr_branch && (branch_res ^ branch_predic_res);

endmodule